/*
	Prototype is developed by Benato Denis.
	Prototype is a project started on 23/09/2013.
	Prototype is release under LGPLv3 license.
	If you use part of Prototype software on other
	projects, you must copy this comment into the source
	code of the other projects, and quote Benato Denis 
	in the credits of the other software.
*/

#include "Prototype.h"

#include "Generator.h"
#include "Program.h"

using namespace std;

int Decompile(char* programFile, char* destinationFile)
{
		FILE *pFile;
		pFile = fopen(programFile, "rb");
		fseek(pFile, 0, SEEK_END);
		unsigned long pFileSize = (unsigned long)ftell(pFile);
		fseek(pFile, 0, SEEK_SET);
		if ((pFileSize >= (sizeof(struct ProgramInfo) + sizeof(struct PrototypeVersion) + sizeof(struct Instruction))) && ((pFileSize - (sizeof(struct ProgramInfo) + sizeof(struct PrototypeVersion))) % sizeof(struct Instruction) == 0))
		{
			struct ProgramInfo CurrentProgramInfo;
			struct PrototypeVersion CompiledPrototypeVersion, CurrentPrototypeVersion = LoadVersionDescriptor();
			fread(&CurrentProgramInfo, sizeof(struct ProgramInfo), 1, pFile);
			fread(&CompiledPrototypeVersion, sizeof(struct PrototypeVersion), 1, pFile);
			if ((CompiledPrototypeVersion.major < CurrentPrototypeVersion.major) || ((CompiledPrototypeVersion.major == CurrentPrototypeVersion.major) && (CompiledPrototypeVersion.minor <= CurrentPrototypeVersion.minor)))
			{
				fstream sFile;
				sFile.open(destinationFile);
				while ((unsigned long)ftell(pFile) != pFileSize)
				{
					struct Instruction CurrentInstruction;
					fread(&CurrentInstruction, sizeof(struct Instruction), 1, pFile);
					int number = (int)CurrentInstruction.data;
					switch (CurrentInstruction.instruction)
					{
						case (unsigned char)0x00:
							sFile << "NOP" << endl;
							break;
						case (unsigned char)0x01:
							sFile << "ADD " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x02:
							sFile << "SUB " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x03:
							sFile << "MUL " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x04:
							sFile << "DIV " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x05:
							sFile << "INPUT" << endl;
							break;
						case (unsigned char)0x06:
							sFile << "OUTPUT" << endl;
							break;
						case (unsigned char)0x07:
							sFile << "IF " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x08:
							sFile << "WHILE " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x09:
							sFile << "END" << endl;
							break;
						case (unsigned char)0x0A:
							sFile << "LDI " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x0B:
							if (CurrentInstruction.data == (unsigned char)0x00)
								sFile << "NOP" << endl;
							else
								sFile << "NEXT " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x0C:
							if (CurrentInstruction.data == (unsigned char)0x00)
								sFile << "NOP" << endl;
							else
								sFile << "PREVIOUS " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x0D:
							if (CurrentInstruction.data == (unsigned char)0x00)
								sFile << "NOP" << endl;
							else
								sFile << "FORWARD " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x0E:
							if (CurrentInstruction.data == (unsigned char)0x00)
								sFile << "NOP" << endl;
							else
								sFile << "BACKWARD " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x0F:
							sFile << "CMP " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x10:
							sFile << "POP" << endl;
							break;
						case (unsigned char)0x11:
							sFile << "PUSH" << endl;
							break;
						case (unsigned char)0x12:
							sFile << "NOT" << endl;
							break;
						case (unsigned char)0x13:
							sFile << "AND " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x14:
							sFile << "OR " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x15:
							sFile << "XOR " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x16:
							sFile << "NAND " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x17:
							sFile << "NOR " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x18:
							sFile << "XNOR " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x19:
							sFile << "RSHIFT " << std::to_string(number) << endl;
							break;
						case (unsigned char)0x20:
							sFile << "LSHIFT " << std::to_string(number) << endl;
							break;
						default:
							sFile << "UNKNOWN " << std::to_string(number) << endl;
							break;
					}
				}
				sFile.close();
				fclose(pFile);
				return 1;
			} else {
				fclose(pFile);
				return 0;
			}
		} else {
			fclose(pFile);
			return -1;
		}
	return -255;
}

